%% @author lsmiao me@lsmiao.com
%% @doc @todo Add description to tr_server.


-module(tr_server).
-behaviour(gen_server).

%%引入测试库
%% ====================================================================
%% API functions
%% ====================================================================
-export([
		start_link/1,start_link/0,get_count/0,stop/0]).
%% gen_server callbacks
-export([init/1,handle_call/3,handle_cast/2,handle_info/2,
		 terminate/2,code_change/3]).
	
-define (SERVER,?MODULE).
-define(DEFAULT_PORT,1055).
-record (stat, {port,lsock,request_count=0}).
%% =====================================================================
%% API
%% ====================================================================
%% Internal functions
%% ====================================================================
start_link(Port) ->
	gen_server:start_link({local,?SERVER}, ?MODULE, [Port], []).
%%派生服务器进程
start_link() ->
	start_link(?DEFAULT_PORT).

get_count() ->
	gen_server:call(?SERVER, get_count).


stop() ->
	gen_server:cast(?SERVER, stop).

init([Port]) ->
	{ok,LSock}=gen_tcp:listen(Port, [{active,true}]),
	{ok,#stat{port=Port,lsock=LSock},0}.
handle_call(get_count,_Form,State)->
	{reply,{ok,State#stat.request_count},State}.
handle_cast(stop,State)->
	{stop,normal,State}.

handle_info({tcp,Socket,RawData},State) ->
	do_rpc(Socket,RawData),
	RequestCount = State#stat.request_count,
	{noreply,State#stat{request_count = RequestCount +1}};
handle_info(timeout,#stat{lsock=LSock} = State) ->
	{ok,_Sock} = gen_tcp:accept(LSock),
	{noreply,State}.
terminate(_Reason,_State) ->
	ok.
code_change(_OldVsn,State,_Extra) ->
	{ok,State}.


do_rpc(Socket,RawData) ->
try
	{M,F,A} = split_out_mfa(RawData),
	Result = apply(M,F,A),
	gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Result]))
catch
	_Class:Err ->
		gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Err]))
end.

split_out_mfa(RawData) ->
	MFA= re:replace(RawData,"\r\n$","",[{return,list}]),
	{match,[M,F,A]}=
		re:run(MFA,
			   "(.*):(.*)\s*\\((.*)\s*\\)\s*.\s*$", 
			   [{capture,[1,2,3],list},ungreedy]), 
	{list_to_atom(M),list_to_atom(F),args_to_terms(A)}.
args_to_terms(RawArgs) ->
	{ok,Toks,_Line} =erl_scan:string("[" ++ RawArgs ++ "].",1),
{ok,Args} =erl_parse:parse_term(Toks),
	Args.

